﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024 LiLong                                                   **
**  This file is part of GnssLogs.                                              **
**                                                                              **
**  GnssLogs is free software: you can redistribute it and/or modify            **
**  it under the terms of the GNU Lesser General Public License as published by **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  GnssLogs is distributed in the hope that it will be useful,                 **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU Lesser General Public License for more details.                         **
**                                                                              **
**  You should have received a copy of the GNU Lesser General Public License    **
**  along with GnssLogs.  If not, see <https://www.gnu.org/licenses/>.          **
**********************************************************************************/
#pragma once

#include "../RAIMSTATUS.h"
#include "LogHeaderDecoder.h"

namespace GnssLogs
{
namespace RAIMSTATUSDecoder
{
using namespace tao::pegtl;
using Sync   = TAO_PEGTL_STRING("#RAIMSTATUSA");
using Header = LogHeaderDecoder::SyncExpression<Sync>;
// clang-format off
struct RAIMMode : ascii::identifier {};
struct IntegrityStatusRule : ascii::identifier {};
struct HPLStatus : ascii::identifier {};
struct HPL : Floating {};
struct VPLStatus : ascii::identifier {};
struct VPL : Floating {};
struct SVS : plus<digit> {};
struct System : ascii::identifier {};
struct SatelliteID : plus<digit> {};
// clang-format on
using Satellite  = seq<Split, System, Split, SatelliteID>;
using Expression = seq<Header,
                       RAIMMode,
                       Split,
                       IntegrityStatusRule,
                       Split,
                       HPLStatus,
                       Split,
                       HPL,
                       Split,
                       VPLStatus,
                       Split,
                       VPL,
                       Split,
                       SVS,
                       star<Satellite>,
                       one<'*'>,
                       CRC32,
                       Tail>;

template<typename T>
struct Action
{
};

template<>
struct Action<Header> : LogHeaderDecoder::LogHeaderHelperNoSetValue
{
};

template<>
struct Action<RAIMMode> : EnumHelper<Action<RAIMMode>, RaimMode>
{
    static void setValue(RAIMSTATUS::Data& data, RaimMode value) { data.raimMode = value; }
};

template<>
struct Action<IntegrityStatusRule> : EnumHelper<Action<IntegrityStatusRule>, IntegrityStatus>
{
    static void setValue(RAIMSTATUS::Data& data, IntegrityStatus value) { data.integrityStatus = value; }
};

template<>
struct Action<HPLStatus> : EnumHelper<Action<HPLStatus>, ProtectionLevelStatus>
{
    static void setValue(RAIMSTATUS::Data& data, ProtectionLevelStatus value) { data.hplStatus = value; }
};

template<>
struct Action<HPL> : DoubleHelper<Action<HPL>>
{
    static void setValue(RAIMSTATUS::Data& data, double value) { data.hpl = value; }
};

template<>
struct Action<VPLStatus> : EnumHelper<Action<VPLStatus>, ProtectionLevelStatus>
{
    static void setValue(RAIMSTATUS::Data& data, ProtectionLevelStatus value) { data.vplStatus = value; }
};

template<>
struct Action<VPL> : DoubleHelper<Action<VPL>>
{
    static void setValue(RAIMSTATUS::Data& data, double value) { data.vpl = value; }
};

template<>
struct Action<SVS> : IntHelper<Action<SVS>, uint32_t>
{
    static void setValue(RAIMSTATUS::Data& data, uint32_t value) { data.svs = value; }
};

template<>
struct Action<System> : EnumHelper<Action<System>, SatelliteSystem>
{
    static void setValue(RAIMSTATUS::Data& data, SatelliteSystem value)
    {
        data.satellites.push_back({});
        data.satellites.back().system = value;
    }
};

template<>
struct Action<SatelliteID> : IntHelper<Action<SatelliteID>, uint32_t>
{
    static void setValue(RAIMSTATUS::Data& data, uint32_t value) { data.satellites.back().id = value; }
};

template<>
struct Action<CRC32> : CRC32Helper<Action<CRC32>>
{
    static void setValue(RAIMSTATUS::Data& data, uint32_t value) { data.crc32 = value; }
};
} // namespace RAIMSTATUSDecoder
} // namespace GnssLogs